package cn.ljy.authority.service.impl;

import cn.ljy.authority.config.security.TokenConfig;
import cn.ljy.authority.dao.mapper.SysConfigMapper;
import cn.ljy.authority.dao.mapper.SysUserMapper;
import cn.ljy.authority.model.SysConfig;
import cn.ljy.authority.model.dto.SysUserAuthority;
import cn.ljy.authority.service.SysUserTokenService;
import cn.ljy.common.exception.model.MyTokenException;
import cn.ljy.common.utils.jwt.JwtUtils;
import cn.ljy.common.utils.redis.StringRedisUtils;
import com.auth0.jwt.interfaces.Claim;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ISysUserTokenService implements SysUserTokenService {

    @Autowired
    private TokenConfig tokenConfig;
    @Autowired
    private SysConfigMapper sysConfigMapper;
    @Autowired
    private StringRedisUtils stringRedisUtils;
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 获取用户对应的key
     * @param userId 客户对象的 id
     * @return
     */
    private String getUserRedisKey(long userId){
        return tokenConfig.getAccessTokenKeyHeader()+userId;
    }

    /**
     * 生成用户的token
     * 说明：设计为通过jwt生成
     * @param userAuthority 对象必须要是从系统中读取
     * @return
     */
    private String createUserToken(SysUserAuthority userAuthority) {
        //设置要携带的信息
        Map<String,Object> claims=new HashMap<>();
        claims.put("userId", userAuthority.getId());
        claims.put("username", userAuthority.getUsername());
        claims.put("nickName", userAuthority.getNickName());
        return JwtUtils.creatToken(claims,tokenConfig.getJwtSecret());//生成token
    }

    @Override
    public String saveUserToken(SysUserAuthority userAuthority) {
        String token=null;
        //生成要存入redis的key值
        String key=this.getUserRedisKey(userAuthority.getId());
        SysConfig config=sysConfigMapper.getByEnable();
        if(config.getAllowLoginInTheSameTime()){//如果允许同时登录
            //先判断redis中有没有key对象
            if(stringRedisUtils.exists(key)) {//如果key还存在，即没有过期
                token = stringRedisUtils.get(key);//获取reids中的token
                //刷新token
                stringRedisUtils.expire(key,tokenConfig.getExpireSeconds(),TimeUnit.SECONDS);
            }else{//如果key不存在
                //生成新的token
                token=this.createUserToken(userAuthority);
                //将token存储到redis中
                stringRedisUtils.set(key,token,tokenConfig.getExpireSeconds(), TimeUnit.SECONDS);
            }
        }else{//如果不允许同时登录
            //生成新的token
            token=this.createUserToken(userAuthority);
            //将token存储到redis中
            stringRedisUtils.set(key,token,tokenConfig.getExpireSeconds(), TimeUnit.SECONDS);
        }
        return token;
    }

    @Override
    public void verifyUserToken(String token) {
        //验证token是否合法
        JwtUtils.verifyToken(token,tokenConfig.getJwtSecret());
        //从token中获取userId，判断传递过来的token是否与系统中保存的token一致
        Claim idClaim=JwtUtils.getClaimByName(token,"userId");//获取token中的userId
        long userId=idClaim.asLong();
        //获取key
        String key=this.getUserRedisKey(userId);
        if(stringRedisUtils.exists(key)) {//如果key还存在，即没有过期
            String tokenOfOld = stringRedisUtils.get(key);//获取reids中的token
            if (!token.equals(tokenOfOld)) {//如果token与原来的token不符，则说明账户已经在不同地方登录，覆盖了原来的token信息
                throw new MyTokenException("您已经被强制下线，如有需要请重新登录");
            }
        }else{
            throw new MyTokenException("token已失效，请重新登录");
        }
    }

    @Override
    public void verifyAndRefreshUserToken(String token) {
        //验证token是否合法
        verifyUserToken(token);
        //从token中获取userId，判断传递过来的token是否与系统中保存的token一致
        Claim idClaim=JwtUtils.getClaimByName(token,"userId");//获取token中的userId
        long userId=idClaim.asLong();
        //获取key
        String key=this.getUserRedisKey(userId);
        //刷新key的时间为最长续航
        stringRedisUtils.expire(key,tokenConfig.getExpireSeconds(),TimeUnit.SECONDS);
    }

    @Override
    public void removeUserToken(SysUserAuthority userAuthority) {
        String key=this.getUserRedisKey(userAuthority.getId());
        stringRedisUtils.remove(key);
    }

    @Override
    public void removeUserToken(String token) {
        if(StringUtils.hasLength(token)){//如果token不为空
            //验证token
            JwtUtils.verifyToken(token,tokenConfig.getJwtSecret());
            String username=JwtUtils.getClaimByName(token,"username").asString();
            //从token中读取账户信息
            Claim idClaim=JwtUtils.getClaimByName(token,"userId");//获取token中的userId
            long userId=idClaim.asLong();
            //移除token
            String key=this.getUserRedisKey(userId);
            stringRedisUtils.remove(key);
        }


    }

    @Override
    public String getUsername(String token) {
        //从token中读取账户信息
        return JwtUtils.getClaimByName(token,"username").asString();
    }
}
